package com.flashflexpro.flexdirector.model{
    import com.flashflexpro.as3lib.EventDictionary;

    import flash.events.Event;
    import flash.utils.Dictionary;

    import mx.collections.ArrayCollection;
    import mx.collections.IList;


    [Bindable]
    [RemoteClass]
    public class DtoTestProcedure extends DtoReusable implements IHasProcedureCaseChildren{

        public function DtoTestProcedure(){
            name = "Unnamed procedure";
            children = new ArrayCollection();
            paramNameToUsagesMap = new EventDictionary();
            appInst2code = new Dictionary();
        }

        public var appInst2code:Dictionary;

        /**
         *
         * "parameter name" ----> [ DtoTestProcedureParameter, _addingCandidateParams ]
         */
        public var paramNameToUsagesMap:EventDictionary;

        /**
         * when a child is removed from children, need to make sure it's usages in parameters also removed!
         */
        public function invalidateParameters():void{
            var toDel:Array = [];
            for( var name:String in paramNameToUsagesMap ){
                var arr:Array = paramNameToUsagesMap[ name ] as Array;
                for( var i:int = arr.length - 1; i >= 0; i -- ){
                    var e:DtoTestProcedureParamUsage = arr[ i ] as DtoTestProcedureParamUsage;
                    if( e.actionable.replayProcedure != null ){
                        arr.splice( i, 1 );
                    }
                }
                if( arr.length == 0 ){
                    toDel.push( name );
                }
            }
            for( var j:int = toDel.length - 1; j >= 0; j-- ){
                delete paramNameToUsagesMap[ toDel[j] ];
            }
        }


        [ArrayElementType("com.flashflexpro.flexdirector.model.IProcedureChild")]
        public var children:ArrayCollection;


        override public function treeWalk( nodeFunc:Function, self:Object = null, parent:NameAndComment = null ):void{
            super.treeWalk( nodeFunc, self, parent );
            if( children != null ){
                for( var i:int = 0; i < children.length; i ++ ){
                    ( children.getItemAt( i ) as NameAndComment ).treeWalk( nodeFunc, self, this );
                }
            }
        }


        override public function copyInto( parent:NameAndComment, newType:Class ):NameAndComment{
            throw new Error( "No! never for procedure!" );
        }

        public function getAppInsts():ArrayCollection{
            var rt:ArrayCollection = new ArrayCollection();
            for each( var obj:* in children ){
                var replay:DtoActionReplay = obj as DtoActionReplay;
                if( replay != null && !rt.contains( replay.appInst ) ){
                    rt.addItem( replay.appInst );
                }
            }
            return rt;
        }


        private var _paramNameList:IList = new ArrayCollection();

        [Bindable(event="paramNameListChanged")]
        public function getParamNameList():IList{
            return _paramNameList;
        }

        public function refreshParamList():void{
            _paramNameList.removeAll();
            for( var paramName:String in paramNameToUsagesMap ){
                _paramNameList.addItem( paramName );
            }
            dispatchEvent( new Event( "paramNameListChanged" ) );
        }

        [Bindable(event="paramNameListChanged")]
        public function getParamNameListByDescType( type:DescProperty ):IList{
            var rt:IList = new ArrayCollection();
            for( var paramName:String in paramNameToUsagesMap ){
                var arr:Array = paramNameToUsagesMap[ paramName ];
                try{
                    if( arr != null && ( arr.length == 0 ) || ( arr.length > 0 &&
                            ( arr[ 0 ] as DtoTestProcedureParamUsage ).getProperty().desc.asType.toLowerCase() ==
                                    type.asType.toLowerCase() ) ){
                        rt.addItem( paramName );
                    }
                }
                catch( e:Error ){
                    trace( this + ".getParamNameListByDescType:" + e.getStackTrace() );
                }
            }
            return rt;
        }

        public function addParamUsage( action:DtoActionReplay, propertyName:String, paramName:String ):Boolean{
            if( paramName == null ){
                throw new Error( this + ".addParamUsage paramName Can't be null!" );
            }
            var arr:Array = paramNameToUsagesMap[ paramName ];
            for each ( var eachUsage:DtoTestProcedureParamUsage in arr ){
                if( eachUsage.actionable == action && eachUsage.propertyName == propertyName ){
                    return false;
                }
            }
            var p:DtoTestProcedureParamUsage = new DtoTestProcedureParamUsage();
            p.actionable = action;
            p.propertyName = propertyName;
            arr.push( p );
            return true;
        }


        public function getParamNameByUsage( action:DtoActionReplay, propertyName:String ):String{
            if( action == null || propertyName == null ){
                return null;
            }
            for( var paramName:String in paramNameToUsagesMap ){
                var arr:Array = paramNameToUsagesMap[ paramName ];
                for each ( var eachParamUsage:DtoTestProcedureParamUsage in arr ){
                    if( eachParamUsage.actionable == action && eachParamUsage.propertyName == propertyName ){
                        return paramName;
                    }
                }
            }
            return null;
        }

        public function removeParamUsage( dtoActionReplay:DtoActionReplay, propertyName:String = null,
                                          paramname:String = null ):void{
            var arr:Array;
            if( paramname != null && propertyName != null ){
                arr = paramNameToUsagesMap[ paramname ];
                if( arr != null ){
                    removeParamUsageFromUsageArr( arr, dtoActionReplay, propertyName );
                }
            }
            else{
                for each ( arr in paramNameToUsagesMap ){
                    removeParamUsageFromUsageArr( arr, dtoActionReplay, propertyName );
                }
            }
        }

        private function removeParamUsageFromUsageArr( arr:Array, dtoActionReplay:DtoActionReplay,
                                                       propertyName:String = null ):void{
            if( arr.length > 0 ){
                for( var i:int = arr.length - 1; i >= 0; i -- ){
                    var eachUsage:DtoTestProcedureParamUsage = arr[ i ];
                    if( eachUsage.actionable == dtoActionReplay &&
                            ( propertyName != null || eachUsage.propertyName == propertyName ) ){
                        arr.splice( i, 1 );
                    }
                }
            }
        }


        public function get version():int{
            return 0;
        }

        public function get lastModifiedTime():uint{
            return 9;
        }

    }
}